<!DOCTYPE html>
<html lang="en-us">
  <head>

    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    
<meta charset="UTF-8">
<title>Scripted Metric Aggregation | Elasticsearch Guide [7.7] | Elastic</title>
<link rel="home" href="index.html" title="Elasticsearch Guide [7.7]">
<link rel="up" href="search-aggregations-metrics.html" title="Metrics Aggregations">
<link rel="prev" href="search-aggregations-metrics-percentile-rank-aggregation.html" title="Percentile Ranks Aggregation">
<link rel="next" href="search-aggregations-metrics-string-stats-aggregation.html" title="String Stats Aggregation">
<meta name="DC.type" content="Learn/Docs/Elasticsearch/Reference/7.7">
<meta name="DC.subject" content="Elasticsearch">
<meta name="DC.identifier" content="7.7">
<meta name="robots" content="noindex,nofollow">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdn.optimizely.com/js/18132920325.js"></script>
    <link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
    <link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
    <link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
    <link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
    <link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
    <link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
    <link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
    <link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
    <link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
    <link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
    <link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
    <link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
    <link rel="manifest" href="/manifest.json">
    <meta name="apple-mobile-web-app-title" content="Elastic">
    <meta name="application-name" content="Elastic">
    <meta name="msapplication-TileColor" content="#ffffff">
    <meta name="msapplication-TileImage" content="/mstile-144x144.png">
    <meta name="theme-color" content="#ffffff">
    <meta name="naver-site-verification" content="936882c1853b701b3cef3721758d80535413dbfd">
    <meta name="yandex-verification" content="d8a47e95d0972434">
    <meta name="localized" content="true">
    <meta name="st:robots" content="follow,index">
    <meta property="og:image" content="https://www.elastic.co/static/images/elastic-logo-200.png">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
    <link rel="icon" href="/favicon.ico" type="image/x-icon">
    <link rel="apple-touch-icon-precomposed" sizes="64x64" href="/favicon_64x64_16bit.png">
    <link rel="apple-touch-icon-precomposed" sizes="32x32" href="/favicon_32x32.png">
    <link rel="apple-touch-icon-precomposed" sizes="16x16" href="/favicon_16x16.png">
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
    <link rel="stylesheet" type="text/css" href="/guide/static/styles.css">
  </head>

  <!--© 2015-2021 Elasticsearch B.V. Copying, publishing and/or distributing without written permission is strictly prohibited.-->

  <body>
    <!-- Google Tag Manager -->
    <script>dataLayer = [];</script><noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-58RLH5" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-58RLH5');</script>
    <!-- End Google Tag Manager -->

    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-12395217-16"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
      gtag('config', 'UA-12395217-16');
    </script>

    <!--BEGIN QUALTRICS WEBSITE FEEDBACK SNIPPET-->
    <script type="text/javascript">
      (function(){var g=function(e,h,f,g){
      this.get=function(a){for(var a=a+"=",c=document.cookie.split(";"),b=0,e=c.length;b<e;b++){for(var d=c[b];" "==d.charAt(0);)d=d.substring(1,d.length);if(0==d.indexOf(a))return d.substring(a.length,d.length)}return null};
      this.set=function(a,c){var b="",b=new Date;b.setTime(b.getTime()+6048E5);b="; expires="+b.toGMTString();document.cookie=a+"="+c+b+"; path=/; "};
      this.check=function(){var a=this.get(f);if(a)a=a.split(":");else if(100!=e)"v"==h&&(e=Math.random()>=e/100?0:100),a=[h,e,0],this.set(f,a.join(":"));else return!0;var c=a[1];if(100==c)return!0;switch(a[0]){case "v":return!1;case "r":return c=a[2]%Math.floor(100/c),a[2]++,this.set(f,a.join(":")),!c}return!0};
      this.go=function(){if(this.check()){var a=document.createElement("script");a.type="text/javascript";a.src=g;document.body&&document.body.appendChild(a)}};
      this.start=function(){var a=this;window.addEventListener?window.addEventListener("load",function(){a.go()},!1):window.attachEvent&&window.attachEvent("onload",function(){a.go()})}};
      try{(new g(100,"r","QSI_S_ZN_emkP0oSe9Qrn7kF","https://znemkp0ose9qrn7kf-elastic.siteintercept.qualtrics.com/WRSiteInterceptEngine/?Q_ZID=ZN_emkP0oSe9Qrn7kF")).start()}catch(i){}})();
    </script><div id="ZN_emkP0oSe9Qrn7kF"><!--DO NOT REMOVE-CONTENTS PLACED HERE--></div>
    <!--END WEBSITE FEEDBACK SNIPPET-->

    <div id="elastic-nav" style="display:none;"></div>
    <script src="https://www.elastic.co/elastic-nav.js"></script>

    <!-- Subnav -->
    <div>
      <div>
        <div class="tertiary-nav d-none d-md-block">
          <div class="container">
            <div class="p-t-b-15 d-flex justify-content-between nav-container">
              <div class="breadcrum-wrapper"><span><a href="/guide/" style="font-size: 14px; font-weight: 600; color: #000;">Docs</a></span></div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="main-container">
      <section id="content">
        <div class="content-wrapper">

          <section id="guide" lang="en">
            <div class="container">
              <div class="row">
                <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                  <!-- start body -->
                  <div class="page_header">
<strong>IMPORTANT</strong>: No additional bug fixes or documentation updates
will be released for this version. For the latest information, see the
<a href="../current/index.html">current release documentation</a>.
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch Guide [7.7]</a></span>
»
<span class="breadcrumb-link"><a href="search-aggregations.html">Aggregations</a></span>
»
<span class="breadcrumb-link"><a href="search-aggregations-metrics.html">Metrics Aggregations</a></span>
»
<span class="breadcrumb-node">Scripted Metric Aggregation</span>
</div>
<div class="navheader">
<span class="prev">
<a href="search-aggregations-metrics-percentile-rank-aggregation.html">« Percentile Ranks Aggregation</a>
</span>
<span class="next">
<a href="search-aggregations-metrics-string-stats-aggregation.html">String Stats Aggregation »</a>
</span>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="search-aggregations-metrics-scripted-metric-aggregation"></a>Scripted Metric Aggregation<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc">edit</a>
</h2>
</div></div></div>
<p>A metric aggregation that executes using scripts to provide a metric output.</p>
<p>Example:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">POST ledger/_search?size=0
{
    "query" : {
        "match_all" : {}
    },
    "aggs": {
        "profit": {
            "scripted_metric": {
                "init_script" : "state.transactions = []", <a id="CO204-1"></a><i class="conum" data-value="1"></i>
                "map_script" : "state.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)",
                "combine_script" : "double profit = 0; for (t in state.transactions) { profit += t } return profit",
                "reduce_script" : "double profit = 0; for (a in states) { profit += a } return profit"
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/382.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO204-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">init_script</code> is an optional parameter, all other scripts are required.</p>
</td>
</tr>
</table>
</div>
<p>The above aggregation demonstrates how one would use the script aggregation compute the total profit from sale and cost transactions.</p>
<p>The response for the above aggregation:</p>
<div class="pre_wrapper lang-console-result">
<pre class="programlisting prettyprint lang-console-result">{
    "took": 218,
    ...
    "aggregations": {
        "profit": {
            "value": 240.0
        }
   }
}</pre>
</div>
<p>The above example can also be specified using stored scripts as follows:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">POST ledger/_search?size=0
{
    "aggs": {
        "profit": {
            "scripted_metric": {
                "init_script" : {
                    "id": "my_init_script"
                },
                "map_script" : {
                    "id": "my_map_script"
                },
                "combine_script" : {
                    "id": "my_combine_script"
                },
                "params": {
                    "field": "amount" <a id="CO205-1"></a><i class="conum" data-value="1"></i>
                },
                "reduce_script" : {
                    "id": "my_reduce_script"
                }
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/383.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO205-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>script parameters for <code class="literal">init</code>, <code class="literal">map</code> and <code class="literal">combine</code> scripts must be specified
in a global <code class="literal">params</code> object so that it can be shared between the scripts.</p>
</td>
</tr>
</table>
</div>
<p>For more details on specifying scripts see <a class="xref" href="modules-scripting.html" title="Scripting">script documentation</a>.</p>
<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="scripted-metric-aggregation-return-types"></a>Allowed return types<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<p>Whilst any valid script object can be used within a single script, the scripts must return or store in the <code class="literal">state</code> object only the following types:</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
primitive types
</li>
<li class="listitem">
String
</li>
<li class="listitem">
Map (containing only keys and values of the types listed here)
</li>
<li class="listitem">
Array (containing elements of only the types listed here)
</li>
</ul>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="scripted-metric-aggregation-scope"></a>Scope of scripts<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<p>The scripted metric aggregation uses scripts at 4 stages of its execution:</p>
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
init_script
</span>
</dt>
<dd>
<p>
Executed prior to any collection of documents. Allows the aggregation to set up any initial state.
</p>
<p>In the above example, the <code class="literal">init_script</code> creates an array <code class="literal">transactions</code> in the <code class="literal">state</code> object.</p>
</dd>
<dt>
<span class="term">
map_script
</span>
</dt>
<dd>
<p>
Executed once per document collected. This is a required script. If no combine_script is specified, the resulting state
needs to be stored in the <code class="literal">state</code> object.
</p>
<p>In the above example, the <code class="literal">map_script</code> checks the value of the type field. If the value is <em>sale</em> the value of the amount field
is added to the transactions array. If the value of the type field is not <em>sale</em> the negated value of the amount field is added
to transactions.</p>
</dd>
<dt>
<span class="term">
combine_script
</span>
</dt>
<dd>
<p>
Executed once on each shard after document collection is complete. This is a required script. Allows the aggregation to
consolidate the state returned from each shard.
</p>
<p>In the above example, the <code class="literal">combine_script</code> iterates through all the stored transactions, summing the values in the <code class="literal">profit</code> variable
and finally returns <code class="literal">profit</code>.</p>
</dd>
<dt>
<span class="term">
reduce_script
</span>
</dt>
<dd>
<p>
Executed once on the coordinating node after all shards have returned their results. This is a required script. The
script is provided with access to a variable <code class="literal">states</code> which is an array of the result of the combine_script on each
shard.
</p>
<p>In the above example, the <code class="literal">reduce_script</code> iterates through the <code class="literal">profit</code> returned by each shard summing the values before returning the
final combined profit which will be returned in the response of the aggregation.</p>
</dd>
</dl>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="scripted-metric-aggregation-example"></a>Worked example<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<p>Imagine a situation where you index the following documents into an index with 2 shards:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">PUT /transactions/_bulk?refresh
{"index":{"_id":1}}
{"type": "sale","amount": 80}
{"index":{"_id":2}}
{"type": "cost","amount": 10}
{"index":{"_id":3}}
{"type": "cost","amount": 30}
{"index":{"_id":4}}
{"type": "sale","amount": 130}</pre>
</div>
<div class="console_widget" data-snippet="snippets/384.console"></div>
<p>Lets say that documents 1 and 3 end up on shard A and documents 2 and 4 end up on shard B. The following is a breakdown of what the aggregation result is
at each stage of the example above.</p>
<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_before_init_script"></a>Before init_script<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc">edit</a>
</h4>
</div></div></div>
<p><code class="literal">state</code> is initialized as a new empty object.</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"state" : {}</pre>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_after_init_script"></a>After init_script<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc">edit</a>
</h4>
</div></div></div>
<p>This is run once on each shard before any document collection is performed, and so we will have a copy on each shard:</p>
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
Shard A
</span>
</dt>
<dd>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"state" : {
    "transactions" : []
}</pre>
</div>
</dd>
<dt>
<span class="term">
Shard B
</span>
</dt>
<dd>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"state" : {
    "transactions" : []
}</pre>
</div>
</dd>
</dl>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_after_map_script"></a>After map_script<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc">edit</a>
</h4>
</div></div></div>
<p>Each shard collects its documents and runs the map_script on each document that is collected:</p>
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
Shard A
</span>
</dt>
<dd>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"state" : {
    "transactions" : [ 80, -30 ]
}</pre>
</div>
</dd>
<dt>
<span class="term">
Shard B
</span>
</dt>
<dd>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"state" : {
    "transactions" : [ -10, 130 ]
}</pre>
</div>
</dd>
</dl>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_after_combine_script"></a>After combine_script<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc">edit</a>
</h4>
</div></div></div>
<p>The combine_script is executed on each shard after document collection is complete and reduces all the transactions down to a single profit figure for each
shard (by summing the values in the transactions array) which is passed back to the coordinating node:</p>
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
Shard A
</span>
</dt>
<dd>
50
</dd>
<dt>
<span class="term">
Shard B
</span>
</dt>
<dd>
120
</dd>
</dl>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_after_reduce_script"></a>After reduce_script<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc">edit</a>
</h4>
</div></div></div>
<p>The reduce_script receives a <code class="literal">states</code> array containing the result of the combine script for each shard:</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"states" : [
    50,
    120
]</pre>
</div>
<p>It reduces the responses for the shards down to a final overall profit figure (by summing the values) and returns this as the result of the aggregation to
produce the response:</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">{
    ...

    "aggregations": {
        "profit": {
            "value": 170
        }
   }
}</pre>
</div>
</div>

</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="scripted-metric-aggregation-parameters"></a>Other parameters<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<div class="informaltable">
<table border="0" cellpadding="4px">
<colgroup>
<col>
<col>
</colgroup>
<tbody valign="top">
<tr>
<td valign="top">
<p>
params
</p>
</td>
<td valign="top">
<p>
</p>
<p>
Optional. An object whose contents will be passed as variables to the  <code class="literal">init_script</code>, <code class="literal">map_script</code> and <code class="literal">combine_script</code>. This can be
useful to allow the user to control the behavior of the aggregation and for storing state between the scripts. If this is not specified,
the default is the equivalent of providing:
</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"params" : {}</pre>
</div>

</td>
</tr>
</tbody>
</table>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="scripted-metric-aggregation-empty-buckets"></a>Empty buckets<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/aggregations/metrics/scripted-metric-aggregation.asciidoc">edit</a>
</h3>
</div></div></div>
<p>If a parent bucket of the scripted metric aggregation does not collect any documents an empty aggregation response will be returned from the
shard with a <code class="literal">null</code> value. In this case the <code class="literal">reduce_script</code>'s <code class="literal">states</code> variable will contain <code class="literal">null</code> as a response from that shard.
<code class="literal">reduce_script</code>'s should therefore expect and deal with <code class="literal">null</code> responses from shards.</p>
</div>

</div>
<div class="navfooter">
<span class="prev">
<a href="search-aggregations-metrics-percentile-rank-aggregation.html">« Percentile Ranks Aggregation</a>
</span>
<span class="next">
<a href="search-aggregations-metrics-string-stats-aggregation.html">String Stats Aggregation »</a>
</span>
</div>
</div>

                  <!-- end body -->
                </div>
                <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                  <div id="rtpcontainer" style="display: block;">
                    <div class="mktg-promo">
                      <h3>Most Popular</h3>
                      <ul class="icons">
                        <li class="icon-elasticsearch-white"><a href="https://www.elastic.co/webinars/getting-started-elasticsearch?baymax=default&amp;elektra=docs&amp;storm=top-video">Get Started with Elasticsearch: Video</a></li>
                        <li class="icon-kibana-white"><a href="https://www.elastic.co/webinars/getting-started-kibana?baymax=default&amp;elektra=docs&amp;storm=top-video">Intro to Kibana: Video</a></li>
                        <li class="icon-logstash-white"><a href="https://www.elastic.co/webinars/introduction-elk-stack?baymax=default&amp;elektra=docs&amp;storm=top-video">ELK for Logs &amp; Metrics: Video</a></li>
                      </ul>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </section>

        </div>


<div id="elastic-footer"></div>
<script src="https://www.elastic.co/elastic-footer.js"></script>
<!-- Footer Section end-->

      </section>
    </div>

<script src="/guide/static/jquery.js"></script>
<script type="text/javascript" src="/guide/static/docs.js"></script>
<script type="text/javascript">
  window.initial_state = {}</script>
  </body>
</html>
